#ifndef _EVENT_LOOP_H_
#define _EVENT_LOOP_H_

#include <cassert>
#include <memory>
#include <vector>

#include "netlib/base/current_thread.h"
#include "netlib/base/mutex.h"
#include "netlib/base/noncopyable.h"
#include "netlib/base/time_stamp.h"
#include "netlib/net/call_backs.h"
#include "netlib/net/timer/timer_index.h"

namespace netlib {

class LogStream;

namespace net {

class Poller;
class Channel;
class TimerQueue;
// class TimerIndex;

class EventLoop : NonCopyable {
public:
	explicit EventLoop(bool is_epoll = false);
	~EventLoop();

	void Loop();
	void Quit() {
		is_quit_ = true;
		if (!IsInLoopThread()) {
			Wakeup();
		}
	}

	bool IsInLoopThread() const {
		int res = current_thread::Tid();
		return kThreadId == res;
	}
	void AssertInLoopThread() {
		if (!IsInLoopThread()) {
			AbortNotInLoopThread();
		}
	}

	void RemoveChannel(Channel* channel);
	void UpdateChannel(Channel* channel);

	void RunInLoop(const Functor& functor);
	void QueueInLoop(const Functor& functor);

	void Wakeup();

	// timer_queue
	TimerIndex RunAt(const Timestamp& time, const TimerCallback& cb);
	TimerIndex RunAfter(double delay, const TimerCallback& cb);
	TimerIndex RunPeriodically(double interval, const TimerCallback& cb);
	void Cancel(TimerIndex timeridx);
	static EventLoop* GetEventLoopOfCurrentThread();

private:
	void AbortNotInLoopThread();
	void HandleWakeup(); // wake up
	void DoPendingFunctors();

	using ChannelVector = std::vector<Channel*>;

	bool is_looping_{false};
	bool is_quit_{false};
	bool is_handling_event_{false};
	bool is_calling_pending_functors_;
	const int kThreadId;
	std::unique_ptr<Poller> poller_;
	ChannelVector activate_channels_;
	TimerQueue* timer_queue_;

	// int wakeup_fd_;
	std::unique_ptr<Channel> wakeup_channel_;
	// Channel* wakeup_channel_;
	mutable MutexLock mutex_;
	std::vector<Functor> pending_functors_ GUARDED_BY(mutex_);

	static const int kPollTimeout;
	static const int64_t kWakeupMsg;
};

LogStream& operator<<(LogStream& stream, EventLoop* loop);

} // namespace net
} // namespace netlib

#endif // _EVENT_LOOP_H_